package cn.dvptech.remotecontrol.screenmirror.virtualDisplay;

import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import timber.log.Timber;

/**
 * Date: 2023/4/23
 * Author: ulongx
 * Project Name: DrivingMate
 * desc: 屏幕显示辅助类
 *  EGL参考 https://www.tabnine.com/code/java/methods/android.opengl.EGL14/eglInitialize
 *  https://www.jianshu.com/p/299d23340528
 */
public class SurfaceTextureHelper implements SurfaceTexture.OnFrameAvailableListener{

    private Callback callback;
    private Surface decodeSurface;
    private EGLSurface mEglSurface;
    private Handler mHandler;
    private HandlerThread mHandlerThread;
    private int mHeight;
    private int mOESTextureId;
    private Surface mSurface;
    private SurfaceTexture mSurfaceTexture;
    private int mWidth;
    private GLXSurfaceRenderer mGLXSurfaceRenderer;
    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;


    public SurfaceTextureHelper(Surface surface, int width, int height){
        this.mSurface = surface;
        this.mWidth = width;
        this.mHeight = height;
        HandlerThread handlerThread = new HandlerThread("SurfaceTextureHelper");
        this.mHandlerThread = handlerThread;
        handlerThread.start();
        this.mHandler = new TextureHandler(this.mHandlerThread.getLooper());
    }

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    // 定义EGL消息常量
    @Retention(RetentionPolicy.SOURCE)
    public @interface EGLMessage {
        int MSG_DESTROY = 300;
        int MSG_INIT = 100;
        int MSG_RENDER = 200;
    }

    public void initEgl() {
        this.mHandler.sendEmptyMessage(EGLMessage.MSG_INIT);
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {

    }

    public interface Callback {
        void notifyDecodeSurface(Surface surface);
    }

    private final class TextureHandler extends Handler {
        public TextureHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message message) {
            int what = message.what;
            if (what == EGLMessage.MSG_INIT) {
                initEGLContext(2);
            } else if (what != EGLMessage.MSG_RENDER) {
            } else {
                updateTexImage();
                drawFrame();
            }
        }
    }

    // 初始化EGL上下文
    public void initEGLContext(int attrib) {
        this.mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); //获取默认显示
        if (this.mEGLDisplay  == EGL14.EGL_NO_DISPLAY) {
            Timber.d( "无法获取EGL14显示: 0x%s", Integer.toHexString(EGL14.eglGetError()));
            return;
        }
        //这里注意写法
        int[] majorVersion = new int[1];
        int[] minorVersion = new int[1];
        if (!EGL14.eglInitialize(this.mEGLDisplay, majorVersion, 0, minorVersion, 0)) {
            Timber.d("无法初始化EGL14: 0x %s", Integer.toHexString(EGL14.eglGetError()));
            return;
        }

        int[] configAttribs = {
                EGL14.EGL_BUFFER_SIZE, 32,
                EGL14.EGL_RED_SIZE, 8,
                EGL14.EGL_GREEN_SIZE, 8,
                EGL14.EGL_BLUE_SIZE, 8,
                EGL14.EGL_ALPHA_SIZE, 8,
                EGL14.EGL_RENDERABLE_TYPE, 4,
                EGL14.EGL_SURFACE_TYPE, 4,
                EGL14.EGL_NONE
        };
        // 所有符合配置的 EGLConfig 个数
        int[] numConfigs = new int[1];
        // 所有符合配置的 EGLConfig
        EGLConfig[] eGLConfigs = new EGLConfig[1];
        if (!EGL14.eglChooseConfig(this.mEGLDisplay, configAttribs, 0, eGLConfigs, 0, eGLConfigs.length, numConfigs, 0)) {
            Timber.d( "无法找到RGB888+可录制ES2 EGL配置: %s", Integer.toHexString(EGL14.eglGetError()));
            return;
        }
        int[] attrib_list = {
                EGL14.EGL_CONTEXT_CLIENT_VERSION, attrib,
                EGL14.EGL_NONE
        };
        // 创建上下文
        this.mEGLContext = EGL14.eglCreateContext(this.mEGLDisplay, eGLConfigs[0], EGL14.EGL_NO_CONTEXT, attrib_list, 0);
        if (this.mEGLDisplay == EGL14.EGL_NO_DISPLAY || this.mEGLContext == EGL14.EGL_NO_CONTEXT) {
            Timber.d(  "上下文为空:%s", EGL14.eglGetError());
            return;
        }
        int[] surfaceAttribs = {
                EGL14.EGL_NONE
        };
        EGLSurface eglCreateWindowSurface = EGL14.eglCreateWindowSurface(this.mEGLDisplay, eGLConfigs[0], this.mSurface, surfaceAttribs, 0);
        this.mEglSurface = eglCreateWindowSurface;
        if (!EGL14.eglMakeCurrent(this.mEGLDisplay, eglCreateWindowSurface, eglCreateWindowSurface, this.mEGLContext)) {
            Timber.d( "表面为空: %s", EGL14.eglGetError());
            return;
        }
        this.mGLXSurfaceRenderer = new GLXSurfaceRenderer();
        this.mGLXSurfaceRenderer.onSurfaceCreated();
        this.mOESTextureId = this.mGLXSurfaceRenderer.getmTextureID();
        this.mSurfaceTexture = new SurfaceTexture(this.mOESTextureId);
        this.mSurfaceTexture.setDefaultBufferSize(this.mWidth, this.mHeight);
        this.mSurfaceTexture.setOnFrameAvailableListener(this);
        Surface surface = new Surface(this.mSurfaceTexture);
        this.decodeSurface = surface;
        Callback callback = this.callback;
        if (callback != null) {
            callback.notifyDecodeSurface(surface);
        }
    }
    public void drawFrame() {
        if (this.mGLXSurfaceRenderer != null) {
            EGLDisplay eGLDisplay = this.mEGLDisplay;
            EGLSurface eGLSurface = this.mEglSurface;
            EGL14.eglMakeCurrent(eGLDisplay, eGLSurface, eGLSurface, this.mEGLContext);
            this.mGLXSurfaceRenderer.onDrawFrame(this.mSurfaceTexture);
            EGL14.eglSwapBuffers(this.mEGLDisplay, this.mEglSurface);
        }
    }
    public void updateTexImage() {
        if (this.mSurfaceTexture != null) {
            this.mSurfaceTexture.updateTexImage();
        }
    }

    public void draw() {
        this.mHandler.sendEmptyMessage(EGLMessage.MSG_RENDER);
    }

}
